package com.lemon.boot.common.utils;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.fill.Property;
import com.lemon.boot.common.base.BaseController;
import com.lemon.boot.common.base.BaseServiceImpl;
import com.lemon.boot.common.consts.ApiConst;
import com.lemon.boot.common.enums.WebTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

/**
 * @author 李猛
 * @datetime 2024/2/29 13:00
 * @description 代码生成工具类
 * 生成配置请查看官方文档，地址：https://baomidou.com/pages/981406/#%E6%95%B0%E6%8D%AE%E5%BA%93%E9%85%8D%E7%BD%AE-datasourceconfig
 */
@Slf4j
public final class GeneratorUtil {

    /**
     * 全局配置
     *
     * @param author 作者
     * @return
     */
    public static Consumer<GlobalConfig.Builder> globalConfig(String author) {
        return builder -> builder
                .outputDir(ApiConst.GENERATOR_JAVA_OUTPUT_DIR)//指定输出目录
                .author(author)//作者名
                .disableOpenDir()//禁止打开输出目录,默认值:true
                .enableSwagger()
                .build();
    }

    /**
     * 策略配置
     *
     * @param tableName   要生成的数据表
     * @param tablePrefix 设置表前缀移除
     * @return
     */
    public static BiConsumer<Function<String, String>, StrategyConfig.Builder> strategyConfig(String tableName, String tablePrefix) {
        return (scanner, builder) -> builder
                .addTablePrefix(tablePrefix)//设置表前缀移除
                .addInclude(tableName)//要生成的数据表
                .controllerBuilder()
                .superClass(BaseController.class)
                .enableRestStyle()
                .mapperBuilder()
                .formatXmlFileName("%sDAO")
                .formatMapperFileName("%sDAO")
                .serviceBuilder()
                .superServiceImplClass(BaseServiceImpl.class)
                .formatServiceFileName("I%sService")
                .formatServiceImplFileName("%sServiceImpl")
                .entityBuilder()
                .versionColumnName("version")
                .versionPropertyName("version")
                .logicDeleteColumnName("deleted")
                .addTableFills(new Column("create_time", FieldFill.INSERT))
                .addTableFills(new Property("updateTime", FieldFill.INSERT_UPDATE))
                .formatFileName("%sPO")
                .enableLombok();
    }

    /**
     * 包配置
     *
     * @return
     */
    public static Consumer<PackageConfig.Builder> packageConfig() {
        return builder -> builder
                .parent(ApiConst.SYSTEM_PACKAGE)
                .entity("po")
                .mapper("dao")
                .xml("dao")
                .service("service")
                .serviceImpl("service.impl")
                .controller("controller")
                .pathInfo(Collections.singletonMap(OutputFile.xml, ApiConst.GENERATOR_XML_OUTPUT_DIR))
                .build();
    }

    /**
     * 配置自定义模板
     *
     * @return
     */
    public static Consumer<TemplateConfig.Builder> templateConfig() {
        return builder -> builder
                .service("/tplgen/service.java")
                .serviceImpl("/tplgen/serviceImpl.java")
                .controller("/tplgen/controller.java")
                .entity("/tplgen/po.java")
                .mapper("/tplgen/dao.java")
                .xml("/tplgen/xml.java")
                .build();
    }

    /**
     * 注入配置
     *
     * @param webTypeEnum web页面类型
     * @return
     */
    public static Consumer<InjectionConfig.Builder> injectionConfig(WebTypeEnum webTypeEnum) {
        Map<String, String> files = new HashMap<>();
        files.put("web", String.format("%stplgen%s%s", File.separator, File.separator, webTypeEnum.getFile()));
        files.put("dto", String.format("%stplgen%sdto.java.vm", File.separator, File.separator));
        return builder -> builder
                .beforeOutputFile((tableInfo, objectMap) -> {
                    String MyModelName = tableInfo.getEntityName().substring(0, tableInfo.getEntityName().length() - 2);
                    String myModelName = MyModelName.substring(0, 1).toLowerCase() + MyModelName.substring(1);
                    objectMap.put("myModelName", MyModelName);
                    objectMap.put("lowModelName", myModelName);
                    objectMap.put("DtoName", MyModelName + "DTO");
                    objectMap.put("dtoName", myModelName + "DTO");

                    //配置页码生成
                    objectMap.put("WebName", MyModelName);
                    objectMap.put("webName", myModelName);
                })
                .customFile(files)
                .build();
    }

    /**
     * 模板引擎配置
     *
     * @param fileOverride 是否开启文件覆盖
     * @param webPath      web路径
     * @return
     */
    public static AbstractTemplateEngine templateEngineConfig(Boolean fileOverride, String webPath) {
        return new VelocityTemplateEngineHandler(fileOverride, webPath);
    }

    /**
     * 生成引擎配置
     */
    private static final class VelocityTemplateEngineHandler extends VelocityTemplateEngine {
        private final Boolean fileOverride;
        private final String webPath;

        public VelocityTemplateEngineHandler(Boolean fileOverride, String webPath) {
            this.fileOverride = fileOverride;
            this.webPath = webPath;
        }

        @Override
        protected void outputCustomFile(List<CustomFile> customFiles, TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
            String entityName = tableInfo.getEntityName().substring(0, tableInfo.getEntityName().length() - 2);
            String pkgName = ApiConst.SYSTEM_PACKAGE.replaceAll("\\.", Matcher.quoteReplacement(File.separator));
            List<CustomFile> dtoFile = customFiles.stream().filter(file -> "dto".equals(file.getFileName())).collect(Collectors.toList());
            List<CustomFile> webFile = customFiles.stream().filter(file -> "web".equals(file.getFileName())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(dtoFile)) {
                dtoFile.forEach(file -> {
                    String fileName = String.format("%s%s%s%sdto%s%sDTO.java", ApiConst.GENERATOR_JAVA_OUTPUT_DIR, File.separator, pkgName, File.separator, File.separator, entityName);
                    outputFile(new File(fileName), objectMap, file.getTemplatePath(), fileOverride);
                });
            }
            if (!CollectionUtils.isEmpty(webFile)) {
                webFile.forEach(file -> {
                    String fileName = String.format("%s%s", webPath, File.separator);
                    outputFile(new File(fileName), objectMap, file.getTemplatePath(), fileOverride);
                });
            }
        }
    }
}
